export interface recType {
  timeOut: number
  asrLanguage?: string
  listener?: (result: string) => void
  onEnd?: () => void
  onStart?: () => void
}
export class Recognition {
  private recognition: any
  private listener?: (result: string) => void
  private isStop = false
  private recOpt: recType = { timeOut: 2000 }
  private handleTime: any
  private hTime: Date | undefined
  private asrLanguage = 'cmn-Hans-CN'
  private onEnd?: () => void
  private onStart?: () => void

  public setListener(fn: (result: string) => void) {
    this.listener = fn
    return this
  }

  public setOnEnd(fn: () => void) {
    this.onEnd = fn
    return this
  }

  public setOpt(opt: recType) {
    this.recOpt = opt
    if (opt.listener)
      this.setListener(opt.listener)
    if (opt.onEnd)
      this.setOnEnd(opt.onEnd)
    if (opt.asrLanguage)
      this.setLang(opt.asrLanguage)
    if (opt.onStart)
      this.onStart = opt.onStart
    return this
  }

  public setLang(lang: string) {
    this.asrLanguage = lang
    return this
  }

  public start() {
    this.isStop = false
    if (
      typeof window === 'undefined'
			|| (!window.SpeechRecognition && !window.webkitSpeechRecognition)
    ) {
      console.warn('当前浏览器不支持 SpeechRecognition，请使用 Chrome 或 Edge')
      return
    }

    if (!this.recognition) {
      const recognition = new (window.SpeechRecognition
				|| window.webkitSpeechRecognition)()
      this.recognition = recognition
    }
    const recognition = this.recognition

    recognition.interimResults = true
    recognition.lang = this.asrLanguage
    recognition.continuous = true

    this.hTime = new Date()
    this.handleTime = setInterval(() => this.check(this), this.recOpt.timeOut)

    recognition.addEventListener('result', (event: any) => {
      let transcript = ''
      for (let index = 0; index < event.results.length; index++) {
        const item = event.results[index]
        if (transcript && this.asrLanguage.includes('Han'))
          transcript += '，'
        transcript += (item as unknown as SpeechRecognitionAlternative[])[0]
          ?.transcript
      }
      if (!transcript)
        return
      this.hTime = new Date()
      this.listener?.(transcript)
    })

    recognition.addEventListener('end', () => {
      if (this.isStop) {
        clearInterval(this.handleTime)
        return
      }
      setTimeout(() => recognition.start(), 1000)
    })

    recognition.start()
    this.onStart?.()
    return this
  }

  private check(that: Recognition) {
    if (!that.hTime)
      return
    const dt = new Date().getTime() - that.hTime.getTime()
    if (dt > that.recOpt.timeOut)
      that.stop() // 只在 stop 中触发 onEnd
  }

  public stop() {
    if (this.isStop)
      return this // 如果已经停止，直接返回
    this.isStop = true
    this.recognition?.stop()
    clearInterval(this.handleTime)
    this.onEnd?.() // 只在这里触发一次 onEnd
    return this
  }

  // public stop() {
  //   this.isStop = true;
  //   this.recognition?.stop();
  //   return this;
  // }

  // private check(that: Recognition) {
  //   if (!that.hTime) return;
  //   const dt = new Date().getTime() - that.hTime.getTime();
  //   if (dt > that.recOpt.timeOut) that.stop();
  // }
}

export const supportLanguages: Record<string, string> = {
  'cmn-Hans-CN': '普通话 (中国大陆)',
  'cmn-Hans-HK': '普通话 (香港)',
  'yue-Hant-HK': '粵語 (香港)',
  'en-US': 'English(United States)',
  'en-GB': 'English(United Kingdom)',
  'en-IN': 'English(India)',
  'es-ES': 'Español',
  'fr-FR': 'Français',
  'de-DE': 'Deutsch',
  'it-IT': 'Italiano',
  'ja-JP': '日本語',
  'ko-KR': '한국어',
  'ar-SA': 'العربية',
  'pt-BR': 'Português',
  'ru-RU': 'Русский',
  'nl-NL': 'Nederlands',
  'tr-TR': 'Türkçe',
  'sv-SE': 'Svenska',
  'hi-IN': 'हिन्दी',
  'el-GR': 'Ελληνικά',
  'he-IL': 'עברית',
  'id-ID': 'Bahasa Indonesia',
  'pl-PL': 'Polski',
  'th-TH': 'ไทย',
  'cs-CZ': 'Čeština',
  'hu-HU': 'Magyar',
  'da-DK': 'Dansk',
  'fi-FI': 'Suomi',
  'no-NO': 'Norsk',
  'sk-SK': 'Slovenčina',
  'uk-UA': 'Українська',
  'vi-VN': 'Tiếng Việt',
}

function sleep(time: number) {
  return new Promise(resolve => setTimeout(resolve, time))
}

// 浏览器文字播放
export async function speakText(
  content: string,
  callback: (playing: boolean) => void,
) {
  if (!window.speechSynthesis)
    return
  if (speechSynthesis.speaking) {
    speechSynthesis.cancel()
    callback(false)
  }

  await sleep(300)

  const msg = new SpeechSynthesisUtterance(content)
  msg.lang = 'zh'
  msg.rate = 1
  msg.addEventListener('end', () => {
    callback(false)
  })
  msg.addEventListener('error', () => {
    callback(false)
  })
  callback(true)
  speechSynthesis.speak(msg)
}
